package jpave.manager;

/************************************************
 * Add remark replaces any existing remark
 * Remove remarks removes all
 * Add file of locations
 */
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

import jpave.annotator.CoreMain;

import assem.Utils;
import util.Debug.ErrorReport;
import util.ui.UserPrompt;

public class AddRemarkPanel extends JPanel {
	private static final long serialVersionUID = -2526722262077846590L;

	private void addLoc(String fileName) {
		// pattern is also in Library.java and AssemMain; used when sequence names are locations
		Pattern mBEDPat = Pattern.compile("(\\S+):(\\d+)-(\\d+)");  // XXX
		System.err.println("Reading location file " + fileName);
		try {
			if (fileName==null || fileName.equals("")) {
				CoreMain.PrtError("Enter filename");
				JOptionPane.showMessageDialog(this, "Enter filename",
						"Error", JOptionPane.PLAIN_MESSAGE);
				return;
			}
			BufferedReader file = new BufferedReader(new FileReader(fileName));
			
			Connection con = theParentFrame.getConnection();
			if (con==null) {
				JOptionPane.showMessageDialog(this, "Cannot open database",
						"Error", JOptionPane.PLAIN_MESSAGE);
				System.err.println("Error: cannot open database");
				return;
			}
			Statement st = con.createStatement();
			
			HashMap <String, Integer> nameIDMap = new HashMap <String, Integer> ();
			ResultSet rs = st.executeQuery("SELECT CTGID, contigid, notes FROM contig");
			while (rs.next()) {
				nameIDMap.put(rs.getString(2), rs.getInt(1));
			}
			if (nameIDMap.size()==0) {
				CoreMain.PrtError("No sequences in database -- run Instantiate");
				JOptionPane.showMessageDialog(this, "No sequences in database -- run Instantiate",
						"Error", JOptionPane.PLAIN_MESSAGE);
				return;
			}
			st.executeUpdate("update assem_msg set pja_msg=NULL");
			st.executeUpdate("update contig set seq_group='', seq_start=0,seq_end=0,seq_strand=''");
			
			String line;
			int add=0, bad1=0, notfound=0;
			
			while((line = file.readLine()) != null) {
				line.replace("\n","");
				if (line.startsWith("#")) {
					System.err.println(line);
					continue;
				}
			
				
				int CID=0;
				String [] tok = line.split("\\s+");
				if (nameIDMap.containsKey(tok[0])) CID = nameIDMap.get(tok[0]);
				else {
					if (notfound < 10) System.err.println("Error no sequence name in database: " + tok[0]);
					notfound++;
					continue;
				}
				String loc = tok[1];
				Matcher m = mBEDPat.matcher(loc);
				if (m.find()) 
				{ 
					String group = m.group(1);
					int start = Integer.parseInt(m.group(2));
					int end = Integer.parseInt(m.group(3));
					String sense="+";
					if (loc.contains("(-)")) sense = "-";
					st.executeUpdate("update contig set seq_group='" + group + 
						"', seq_start=" + start + ",seq_end=" + end +  ",seq_strand='" + sense + "'" +
						" where CTGID=" + CID); 
					add++;
				} else {
					if (bad1 < 10) System.err.println("Bad location: " + loc);
					bad1++;	
				}
				int x = add+bad1;
				if (x % 1000 == 0) System.err.print("     Add " + add + " Not found " + bad1 + "\r"); 
			}	
			
			rs = st.executeQuery("show columns from assem_msg like 'hasLoc'");
			if (!rs.first()) 
				st.executeUpdate("alter table assem_msg add hasLoc tinyint");
			
			st.close();
			System.err.println("Added " + add + " locations to the database");
			if (bad1>0) System.err.println("Ignored lines " + bad1);
			if (notfound>0) System.err.println("No sequence IDs in database " + notfound);
		}
		catch (Exception e) {ErrorReport.reportError(e, "Reading location file " + fileName);}		
	}
	private void addRemark(String fileName) {
		try {
			if (fileName==null || fileName.equals("")) {
				CoreMain.PrtError("Enter filename");
				JOptionPane.showMessageDialog(this, "Enter filename",
						"Error", JOptionPane.PLAIN_MESSAGE);
				return;
			}
			
			Pattern pat = Pattern.compile("(\\S+)\\s+(.*)$"); 
			System.err.println("Reading remark file " + fileName);
			Connection con = theParentFrame.getConnection();
			if (con==null) {
				System.err.println("Error: cannot open database");
				JOptionPane.showMessageDialog(this, "Cannot open database",
						"Error", JOptionPane.PLAIN_MESSAGE);
				return;
			}
			Statement st = con.createStatement();
			
			HashMap <String, Integer> ctgMap = new HashMap <String, Integer> ();
			HashMap <Integer,String> ctgMap2 = new HashMap <Integer, String> ();
			HashMap<Integer,String> curRems = new HashMap<Integer,String>();
			ResultSet rs = st.executeQuery("SELECT CTGID, contigid, notes FROM contig");
			while (rs.next()) {
				ctgMap.put(rs.getString(2), rs.getInt(1));
				ctgMap2.put(rs.getInt(1), rs.getString(2));
				String rem = (rs.getString(3) == null ? "" : rs.getString(3).trim());
				if (!rem.equals(""))
				{
					curRems.put(rs.getInt(1),rem);
				}
			}
			if (ctgMap.size()==0) {
				CoreMain.PrtError("No sequences in database -- run Instantiate");
				JOptionPane.showMessageDialog(this, "No sequences in database -- run Instantiate",
						"Error", JOptionPane.PLAIN_MESSAGE);
				return;
			}
				
			BufferedReader file = new BufferedReader(new FileReader(fileName));
			String line;
			int cnt=0, add=0, append=0, bad1=0, notfound=0;
			
			Vector<String> longRems = new Vector<String>();
			while((line = file.readLine()) != null) {
				line.replace("\n","");
				if (line.startsWith("#")) {
					System.err.println(line);
					continue;
				}
				cnt++;
				if (cnt % 1000 == 0) System.err.print("   Read " + cnt + "\r");
				if (line.contains("\"") || line.contains("\'")) {
					line = line.replace("\"", " ");
					line = line.replace("\'", " ");
					System.err.println("Replacing single and double quotes with blanks: " + line);
				}	
				
				Matcher m = pat.matcher(line);
				if (!m.find()) { bad1++; continue;} 
				String name = m.group(1).trim();
				String value = m.group(2).trim();
				int CID=0;
				
				if (ctgMap.containsKey(name)) CID = ctgMap.get(name);
				else {
					String tmp = name;
					Pattern mNameFixPat = Pattern.compile("[^\\w\\.]");
					Matcher mm = mNameFixPat.matcher(tmp);
					name =  mm.replaceAll("_");
					if (tmp.equals(name)) {
						if (notfound < 10) System.err.println("Error no sequence name in database " + name);
						notfound++;
						continue;
					}
					else {
						if (ctgMap.containsKey(name)) CID = ctgMap.get(name);
						else {
							if (notfound < 10) System.err.println("Error no sequence name in database " + tmp + " or " + name);
							notfound++;
							continue;
						}
					}
				}				
				if (curRems.containsKey(CID))
				{
					value = curRems.get(CID) + ";" + value;
					append++;
				}
				else add++;
				if (value.length() > 250)
				{
					longRems.add(name);
					value = value.substring(0, 250);
				}
				curRems.put(CID, value);
			}
			System.err.println("Complete reading file");
			for (int CID : curRems.keySet())
			{
				String value = curRems.get(CID);
				try {
					st.executeUpdate("UPDATE contig SET notes='" + value + "'" +
						" WHERE CTGID=" + CID);
		
				} catch (Exception e){
					ErrorReport.die("Error entering remark for " + ctgMap2.get(CID));
				}
				if (cnt%1000 == 0) System.err.print("   Read " + cnt + "  Add " + add + " append " + append + "\r");
			}
			st.close();
			System.err.println("Added " + (add + append) +" remarks to the database");
			if (bad1>0) System.err.println("Ignored lines " + bad1);
			if (notfound>0) System.err.println("No sequence IDs in database " + notfound);
			if (longRems.size() > 0)
			{
				System.err.println(longRems.size() + " contigs had remarks longer than 250 chars and were truncated:");
				System.err.println(Utils.strVectorJoin(longRems, ","));
			}
		} catch (Exception e) {
			ErrorReport.reportError(e, "Reading remark file " + fileName);
		}
	}
	
	private void removeRemark() {
		try {
			Connection con = theParentFrame.getConnection();
			Statement st = con.createStatement();
			st.executeUpdate("Update contig set notes=''");
			st.close();
			System.err.println("Removed remarks");
		}
		catch (Exception e) {ErrorReport.reportError(e, "Error removing remarks");}
	}
	
	/****************************************************************
	 * Panel
	 */
	public AddRemarkPanel(ManagerFrame parentFrame) {
		theParentFrame = parentFrame;
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		setBackground(Color.WHITE);
		
		JPanel titleRow = new JPanel();
		titleRow.setLayout(new BoxLayout(titleRow, BoxLayout.LINE_AXIS));
		titleRow.setBackground(Color.WHITE);
		JLabel title = new JLabel("Remarks or Locations");
		title.setFont(getFont().deriveFont(Font.BOLD, 18));
		title.setBackground(Color.WHITE);
		titleRow.add(title);
		titleRow.setMaximumSize(titleRow.getPreferredSize());
		titleRow.setMinimumSize(titleRow.getPreferredSize());
		add(titleRow);
		add(Box.createVerticalStrut(20));
		
		JPanel fileNameRow = new JPanel();
		fileNameRow.setLayout(new BoxLayout(fileNameRow, BoxLayout.LINE_AXIS));
		fileNameRow.setBackground(Color.WHITE);
		fileNameRow.add(new JLabel("File name"));
		fileNameRow.add(Box.createHorizontalStrut(5));
		txtFile = new FileTextField(30);
		txtFile.setAlignmentX(Component.CENTER_ALIGNMENT);
		txtFile.addCaretListener(new CaretListener() {
			public void caretUpdate(CaretEvent arg0) {
				boolean enable = false;
				enable = txtFile.getText().length() > 0;
				btnAdd.setEnabled(enable);
				btnLoc.setEnabled(enable);
				btnRemove.setEnabled(true);
			}
		});
		fileNameRow.add(txtFile);
		fileNameRow.setMaximumSize(fileNameRow.getPreferredSize());
		fileNameRow.setMinimumSize(fileNameRow.getPreferredSize());
		add(fileNameRow);
		add(Box.createVerticalStrut(10));
		
		JPanel addRow = new JPanel();
		addRow.setLayout(new BoxLayout(addRow, BoxLayout.LINE_AXIS));
		addRow.setBackground(Color.WHITE);
		btnAdd = new JButton("Add Remarks from File");
		btnAdd.setBackground(Color.WHITE);
		btnAdd.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				addRemark(txtFile.getText());
				setVisible(false);
				theParentFrame.setMainPanelVisible(true);
			}
		});
		btnLoc = new JButton("Add Locations from File");
		btnLoc.setBackground(Color.WHITE);
		btnLoc.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				addLoc(txtFile.getText());
				setVisible(false);
				theParentFrame.setMainPanelVisible(true);
			}
		});
		addRow.add(btnAdd);
		addRow.add(Box.createHorizontalStrut(10));
		addRow.add(btnLoc);
		addRow.setMaximumSize(addRow.getPreferredSize());
		addRow.setMinimumSize(addRow.getPreferredSize());
		add(addRow);
		add(Box.createVerticalStrut(10));
		
		JPanel buttonRow = new JPanel();
		buttonRow.setLayout(new BoxLayout(buttonRow, BoxLayout.LINE_AXIS));
		buttonRow.setBackground(Color.WHITE);
		
		btnRemove = new JButton("Remove Remarks");
		btnRemove.setBackground(Color.WHITE);
		btnRemove.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setVisible(false);
				removeRemark();
				theParentFrame.setMainPanelVisible(true);
			}
		});
		buttonRow.add(btnRemove);
		buttonRow.add(Box.createHorizontalStrut(10));
		btnClose = new JButton("Close");
		btnClose.setBackground(Color.WHITE);
		btnClose.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				setVisible(false);
				theParentFrame.setMainPanelVisible(true);
			}
		});
		buttonRow.add(btnClose);
		buttonRow.add(Box.createHorizontalStrut(10));

		btnHelp = new JButton("Help");
		btnHelp.setBackground(ManagerFrame.HELPCOLOR);
		btnHelp.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				UserPrompt.displayHTMLResourceHelp(theParentFrame, "Remark Help", 
						"html/runSingleTCW/RemarkHelp.html");
			}
		});
		buttonRow.add(btnHelp);
		buttonRow.setMaximumSize(buttonRow.getPreferredSize());
		buttonRow.setMinimumSize(buttonRow.getPreferredSize());
		add(buttonRow);
		
		setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
	}
	
	public void reset() {
		txtFile.setText("");
		btnAdd.setEnabled(false);
		btnLoc.setEnabled(false);
		btnRemove.setEnabled(true);
	}
	
	public void setStartingDir(File dir) {
		startingDir = dir;
	}
	
	private AddRemarkPanel getInstance() { return this; }
	private FileTextField txtFile = null;
	private JButton btnAdd = null;
	private JButton btnLoc = null;

	private JButton btnRemove = null;
	private JButton btnClose = null;
	private JButton btnHelp = null;
	
	private ManagerFrame theParentFrame = null;
	private File startingDir = null;
	
	private class FileTextField extends JPanel {
		private static final long serialVersionUID = 6670096855895700182L;
		
		public FileTextField(int size) {
			setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
			setAlignmentX(Component.LEFT_ALIGNMENT);
			setBackground(ManagerFrame.BGCOLOR);
			
			txtValue = new JTextField(size);
			Dimension dTxt = txtValue.getPreferredSize(); 
			txtValue.setMaximumSize(dTxt);
			txtValue.setMinimumSize(dTxt);
			
			btnFindFile = new JButton("...");
			btnFindFile.setBackground(ManagerFrame.BGCOLOR);
			Dimension dBtn = new Dimension();
			dBtn.width = btnFindFile.getPreferredSize().width;
			dBtn.height = dTxt.height;
			
			btnFindFile.setMaximumSize(dBtn);
			btnFindFile.setMinimumSize(dBtn);
			btnFindFile.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					try {
						JFileChooser fc = new JFileChooser();

						if(startingDir != null)
							fc.setCurrentDirectory(startingDir);

						if(fc.showOpenDialog(getInstance()) == JFileChooser.APPROVE_OPTION) {
							txtValue.setText(fc.getSelectedFile().getPath());
						}
					}
					catch(Exception e) {
						ErrorReport.prtReport(e, "Error finding file");
					}
					
				}});
			
			add(txtValue);
			add(btnFindFile);
		}
		
		public void addCaretListener(CaretListener l) { txtValue.addCaretListener(l); }
		
		public void setEnabled(boolean enabled) { 
			txtValue.setEnabled(enabled);
			btnFindFile.setEnabled(enabled);
		}
		
		public void setText(String text) { txtValue.setText(text); }
		public String getText() { return txtValue.getText(); }
		
		private JTextField txtValue = null;
		private JButton btnFindFile = null;
	}

}
